
'use strict'

let {guid} = require('../utils')

module.exports = function(handler){
    
    let {impl, Model, extra_map, boy} = handler

    // 通过json来更新boy, 或者将boy转换为json
    impl(Model, '$json', function(json){
        if(undefined === json){
            let res = {}
            for(let key in this){
                if(this[key] instanceof Array){
                    let arr = []
                    this[key].forEach(elem=>{
                        arr.push(elem.$json ? elem.$json() : elem)
                    })
                    res[key] = arr
                }else if(this[key].$type && 'BOY_MODEL' === this[key].$type()){
                    res[key] = this[key].$json()
                }else{
                    res[key] = this[key]
                }
            }
            return res
        }
        // 以上内容已短路

        
    })


    impl(Model, '_destory', function(){

        this.$extra().destory()
        delete extra_map[this.$guid()]

        for(let key in this){
            if(this[key] instanceof Array){
                for(let elem of this[key]){
                    elem._destory && elem._destory()
                }
            }else{
                this[key]._destory && this[key]._destory()
            }
        }
    })

    impl(Model, '$destory', function(){

        // 并不希望通过boy对象持有者删除boy, 不符合我的设计理念

        // 如果这个boy在数组中, 先将其游离出来

        if(this.$index() > 0){
            let point = this.$point()
            let mount = this.$mount()
            mount[point].splice(this.$index(), 1)
        }
        this._destory()
    })

    // 创建一组对象
    impl(Model, '_create', function(val, key){
        let res = []
        if(val instanceof Array){
            val.forEach(elem => {
                if('object' === typeof elem){
                    elem.mount = this
                    elem.point = key
                    res.push(boy.createByJson(elem))
                }else{
                    res.push(boy.createByCmd(elem, this, key))
                }
            })
        }else if('object' === typeof val){
            val.mount = this
            val.point = key
            res.push(boy.createByJson(val))
        }else{
            res.push(boy.createByCmd(val, this, key))
        }
        return res
    })

    impl(Model, '$set', function(key, val){

        // 先对该字段执行清理
        if(this[key] instanceof Array){
            this[key].forEach(elem => {
                elem._destory && elem._destory()
            })
        }else if(this[key] && this[key].$type && 'BOY_MODEL' === this[key].$type()){
            this[key]._destory()
        }

        // 再赋新值
        this[key] = val instanceof Array ? this._create(val, key) : this._create(val, key).pop()
    })

    // 插入一组对象
    impl(Model, '$insert', function(param, val, callback){

        if(undefined === callback){
            callback = this.$everyboy
        }
        if(noBoy === callback()){
            return (this[param] = this._create(val, param).concat(this[param]))
        }
        if(everyBoy === callback()){
            return (this[param] = this[param].concat(this._create(val, param)))
        }
        // 以上短路


        let index_i = callback
        if('function' === typeof callback){
            for(let [elem, index] of Object.entries(this[param])){
                if(callback(elem, index)){
                    break
                }else{
                    index_i = index
                }
            }
        }
        let res = this._create(val)
        this[param].splice.apply(this, [index_i, 0].concat(res))
    })

    let noBoy = guid()
    let everyBoy = guid()
    impl(Model, '$noboy', function(){
        return noBoy
    })
    impl(Model, '$everyboy', function(){
        return everyBoy
    })

    impl(Model, '$each', function(key, callback){
    
        for(let elem of this[key]){
            if(eachEnd === callback(elem)){
                break
            }
        }
        return this
    })

    let eachEnd = guid()
    impl(Model, '$eachEnd', function(){
        return eachEnd
    })
}